package com.uinnova.product.eam.service.impl;

import com.binary.core.exception.BinaryException;
import com.binary.core.util.BinaryUtils;
import com.google.common.collect.Lists;
import com.uinnova.product.eam.comm.model.es.AssetWarehouseDir;
import com.uinnova.product.eam.model.AssetWarehouseDirVo;
import com.uinnova.product.eam.service.AssetWarehouseDirSvc;
import com.uinnova.product.eam.service.EamCategorySvc;
import com.uinnova.product.eam.service.IEamDiagramSvcV2;
import com.uinnova.product.eam.service.es.AssetWarehouseDirDao;
import com.uino.bean.permission.base.SysRole;
import com.uino.bean.permission.base.SysRoleModuleRlt;
import com.uino.bean.permission.business.ModuleNodeInfo;
import com.uino.dao.permission.ESRoleSvc;
import com.uino.dao.permission.rlt.ESRoleModuleRltSvc;
import com.uino.dao.util.ESUtil;
import com.uino.service.permission.microservice.IModuleSvc;
import com.uino.util.sys.BeanUtil;
import com.uino.util.sys.SysUtil;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class AssetWarehouseDirSvcImpl implements AssetWarehouseDirSvc {

    @Resource
    AssetWarehouseDirDao assetWarehouseDirDao;

    @Resource
    EamCategorySvc categorySvc;

    @Autowired
    private ESRoleSvc roleSvc;
    @Resource
    IEamDiagramSvcV2 eamDiagramSvcV2;

    @Resource
    IModuleSvc moduleSvc;

    @Autowired
    ESRoleModuleRltSvc roleModuleRltSvc;

    @Override
    public Integer saveOrUpdate(List<AssetWarehouseDirVo> assetWarehouseDirs) {
//        List<AssetWarehouseDir> oldAssetDir = assetWarehouseDirDao.getListByQuery(null);
//        Map<Long, List<AssetWarehouseDir>> parentGroup = oldAssetDir.stream().collect(Collectors.groupingBy(AssetWarehouseDir::getParentId));
        List<AssetWarehouseDir> newDirList = new ArrayList<>();
        // 创建顶级目录文件夹
        List<AssetWarehouseDir> createCateGoryList = new ArrayList<>();
        // 填充目录信息
        fillAndCheckAssetDir(assetWarehouseDirs, 0L, newDirList, createCateGoryList, 0);
        // 重名校验
        Map<Long, List<AssetWarehouseDir>> group = newDirList.stream().collect(Collectors.groupingBy(AssetWarehouseDir::getParentId));
        for (Long id : group.keySet()) {
            List<AssetWarehouseDir> warehouseDirs = group.get(id);
            List<String> names = new ArrayList<>();
            for (AssetWarehouseDir warehouseDir : warehouseDirs) {
                if (names.contains(warehouseDir.getName())) {
                    throw new BinaryException("目录名称：【" + warehouseDir.getName() + "】重复");
                }
                names.add(warehouseDir.getName());
            }
        }
        Integer num = assetWarehouseDirDao.saveOrUpdateBatch(newDirList);
        if (!CollectionUtils.isEmpty(createCateGoryList)) {
            categorySvc.createTopCategoryByAssetDir(createCateGoryList);
        }
        return num;
    }

    private void fillAndCheckAssetDir(List<AssetWarehouseDirVo> assetWarehouseDirs, Long parentDirId,
                                      List<AssetWarehouseDir> newDirList, List<AssetWarehouseDir> createCateGoryList, int order) {
        for (AssetWarehouseDirVo dirVo : assetWarehouseDirs) {
            checkNotEmptyProperty(dirVo);
            AssetWarehouseDir target = new AssetWarehouseDir();
            BeanUtil.copyProperties(dirVo, target);
            target.setOrderNo(order++);
            target.setParentId(parentDirId);
            if (BinaryUtils.isEmpty(target.getId())) {
                target.setId(ESUtil.getUUID());
                target.setCreateTime(System.currentTimeMillis());
                target.setCreator(SysUtil.getCurrentUserInfo().getLoginCode());
                if (target.getModuleType() == 3) {
//                    int code = ("QUICK_EA" + target.getName()).hashCode() & Integer.MAX_VALUE;
                    String moduleUrl = target.getModuleUrl();
                    String substring = moduleUrl.substring(0, moduleUrl.indexOf("assets/") + 7);
                    target.setModuleUrl(substring + "{" + target.getId() + "}" + "?id=" + target.getId());
                }
            } else {
                if (target.getModuleType() == 3) {
                    if (!target.getModuleUrl().contains("=")) {
                        String moduleUrl = target.getModuleUrl();
                        String substring = moduleUrl.substring(0, moduleUrl.indexOf("assets/") + 7);
                        target.setModuleUrl(substring + "{" + target.getId() + "}" + "?id=" + target.getId());
                    }
                }
            }
            // 在目录文件夹中创建顶级目录
            if (target.getModuleType() == 3) {
                createCateGoryList.add(target);
            }
            target.setModifyTime(System.currentTimeMillis());
            target.setModifier(SysUtil.getCurrentUserInfo().getLoginCode());
            target.setDomainId(SysUtil.getCurrentUserInfo().getDomainId());
            newDirList.add(target);
            if (!CollectionUtils.isEmpty(dirVo.getChildren())) {
                fillAndCheckAssetDir(dirVo.getChildren(), target.getId(), newDirList, createCateGoryList, 0);
            }

        }
    }

    private void checkNotEmptyProperty(AssetWarehouseDirVo dirVo) {
        if (BinaryUtils.isEmpty(dirVo.getName())) {
            throw new BinaryException("目录名称,不可为空");
        }
        BinaryUtils.checkEmpty(dirVo.getModuleType(), "目录类型");
        if (3 == dirVo.getModuleType()) {
            if (CollectionUtils.isEmpty(dirVo.getRoleIdList())) {
                throw new BinaryException("【" + dirVo.getName() + "】权限配置,不可为空");
            }
            if (BinaryUtils.isEmpty(dirVo.getAssetType())) {
                throw new BinaryException("【" + dirVo.getName() + "】资产类型,不可为空");
            }
            BinaryUtils.checkEmpty(dirVo.getModuleUrl(), "【" + dirVo.getName() + "】页面配置");
        }
    }

    @Override
    public Integer delete(Long id) {
        AssetWarehouseDir dir = assetWarehouseDirDao.getById(id);
        if (BinaryUtils.isEmpty(dir)) {
            throw new BinaryException("目录已被删除");
        }
        List<Long> categoryIdList = new ArrayList<>();
        List<Long> dirIdList = new ArrayList<>();
        dirIdList.add(dir.getId());
        if (!dir.getModuleType().equals(3)) {
            // 获取分组下的页面对应目录Id集合
            List<AssetWarehouseDir> assetDirs = assetWarehouseDirDao.getListByQuery(null);
            Map<Long, List<AssetWarehouseDir>> parentIdGroup = assetDirs.stream().collect(Collectors.groupingBy(AssetWarehouseDir::getParentId));
            fillChildrenPageList(parentIdGroup, dir, categoryIdList, dirIdList);
        } else {
            // 查询资产仓库目录中是否存在资产
            String moduleUrl = dir.getModuleUrl();
            String[] split = moduleUrl.split("=");
            Long categoryId = Long.valueOf(split[split.length - 1]);
            categoryIdList.add(categoryId);
        }
        boolean ifExist = eamDiagramSvcV2.checkDirExistData(categoryIdList);
        if (ifExist) {
            throw new BinaryException("该目录下存在资产，请删除资产信息后再进行目录删除");
        }
        // 删除目录
        return assetWarehouseDirDao.deleteByIds(dirIdList);
    }

    private void fillChildrenPageList(Map<Long, List<AssetWarehouseDir>> parentIdGroup, AssetWarehouseDir dir, List<Long> categoryIdList, List<Long> dirIdList) {
        List<AssetWarehouseDir> childrenList = parentIdGroup.get(dir.getId());
        if (!BinaryUtils.isEmpty(childrenList)) {
            for (AssetWarehouseDir dirChildren : childrenList) {
                if (dir.getModuleType().equals(3)) {
                    String moduleUrl = dirChildren.getModuleUrl();
                    String[] split = moduleUrl.split("=");
                    Long categoryId = Long.valueOf(split[split.length - 1]);
                    categoryIdList.add(categoryId);
                } else {
                    fillChildrenPageList(parentIdGroup, dirChildren, categoryIdList, dirIdList);
                }
                dirIdList.add(dirChildren.getId());
            }
        }
    }

    @Override
    public List<AssetWarehouseDirVo> getTree(Long userId) {
        List<AssetWarehouseDirVo> result = new ArrayList<>();
        List<AssetWarehouseDir> assetWarehouseDirs = assetWarehouseDirDao.getListByQuery(null);
        if (BinaryUtils.isEmpty(userId)) {
            // 返回所有目录树
            listToDirTree(result, assetWarehouseDirs);
        } else {
            // 返回用户具有权限的目录树
            List<SysRole> roles = roleSvc.getListByUserId(userId);
            if (!BinaryUtils.isEmpty(roles)) {
                // 找出这些角色有的模块权限加进去
                List<Long> roleIds = roles.stream().map(SysRole::getId).collect(Collectors.toList());
                Iterator<AssetWarehouseDir> iterator = assetWarehouseDirs.iterator();
                while (iterator.hasNext()) {
                    AssetWarehouseDir next = iterator.next();
                    if (next.getModuleType().equals(3)) {
                        if (!containsAny(next.getRoleIdList(), roleIds)) {
                            iterator.remove();
                        }
                    }
                }
            }
            listToDirTree(result, assetWarehouseDirs);
        }
        // 排序
        sortDirTree(result);
        return result;
    }

    private void sortDirTree(List<AssetWarehouseDirVo> result) {
        if (CollectionUtils.isEmpty(result)) {
            return;
        }
        result.sort(Comparator.comparing(AssetWarehouseDir::getOrderNo));
        for (AssetWarehouseDirVo assetWarehouseDirVo : result) {
            sortDirTree(assetWarehouseDirVo.getChildren());
        }
    }

    private void listToDirTree(List<AssetWarehouseDirVo> result, List<AssetWarehouseDir> assetWarehouseDirs) {
        // 过滤不包换页面的分组
        List<AssetWarehouseDir> assetPageList = assetWarehouseDirs.stream().filter(assetWarehouseDir -> assetWarehouseDir.getModuleType().equals(3)).collect(Collectors.toList());
        Map<Long, AssetWarehouseDir> dirIdMap = assetWarehouseDirs.stream().collect(Collectors.toMap(AssetWarehouseDir::getId, e -> e, (k1, k2) -> k1));
        List<AssetWarehouseDir> dirArrayList = new ArrayList<>(assetPageList);
        // 寻找分组到根目录
        for (AssetWarehouseDir assetWarehouseDir : assetPageList) {
            getParentDir(dirArrayList, dirIdMap, assetWarehouseDir);
        }
        Map<Long, List<AssetWarehouseDir>> parentIdGroup = dirArrayList.stream().collect(Collectors.groupingBy(AssetWarehouseDir::getParentId));
        List<AssetWarehouseDir> dirList = parentIdGroup.get(0L);
        if (!CollectionUtils.isEmpty(dirList)) {
            for (AssetWarehouseDir assetWarehouseDir : dirList) {
                AssetWarehouseDirVo target = new AssetWarehouseDirVo();
                BeanUtil.copyProperties(assetWarehouseDir, target);
                fillChildren(parentIdGroup, target);
                result.add(target);
            }
        }
    }

    private void getParentDir(List<AssetWarehouseDir> dirArrayList, Map<Long, AssetWarehouseDir> dirIdMap, AssetWarehouseDir assetWarehouseDir) {
        AssetWarehouseDir dir = dirIdMap.get(assetWarehouseDir.getParentId());
        if (!BinaryUtils.isEmpty(dir)) {
            getParentDir(dirArrayList, dirIdMap, dir);
            if (!dirArrayList.contains(dir)) {
                dirArrayList.add(dir);
            }
        }
    }


    private void fillChildren(Map<Long, List<AssetWarehouseDir>> parentIdGroup, AssetWarehouseDirVo target) {
        Long parentNodeId = target.getId();
        List<AssetWarehouseDir> childrenList = parentIdGroup.get(parentNodeId);
        if (!BinaryUtils.isEmpty(childrenList)) {
            target.setChildren(BeanUtil.converBean(childrenList, AssetWarehouseDirVo.class));
            for (AssetWarehouseDirVo dirVo : target.getChildren()) {
                fillChildren(parentIdGroup, dirVo);
            }
        }
    }

    public static boolean containsAny(List<?> list1, List<?> list2) {
        if (CollectionUtils.isEmpty(list1) || CollectionUtils.isEmpty(list2)) {
            return false;
        }
        return !Collections.disjoint(list1, list2);
    }

    @Override
    public List<AssetWarehouseDirVo> getConfigTree() {
        List<AssetWarehouseDirVo> result = new ArrayList<>();
        List<AssetWarehouseDir> assetWarehouseDirs = assetWarehouseDirDao.getListByQuery(null);
        Map<Long, List<AssetWarehouseDir>> parentIdGroup = assetWarehouseDirs.stream().collect(Collectors.groupingBy(AssetWarehouseDir::getParentId));
        List<AssetWarehouseDir> dirList = parentIdGroup.get(0L);
        if (!CollectionUtils.isEmpty(dirList)) {
            for (AssetWarehouseDir assetWarehouseDir : dirList) {
                AssetWarehouseDirVo target = new AssetWarehouseDirVo();
                BeanUtil.copyProperties(assetWarehouseDir, target);
                fillChildren(parentIdGroup, target);
                result.add(target);
            }
        }
        return result;
    }


    @Override
    public List<AssetWarehouseDir> getListByRoleIds(List<Long> roleIdList) {
        List<AssetWarehouseDir> pageDirList = assetWarehouseDirDao.getListByQuery(QueryBuilders.termQuery("moduleType", 3));
        if (CollectionUtils.isEmpty(pageDirList)) {
            return Collections.emptyList();
        }
        List<AssetWarehouseDir> result = new ArrayList<>();
        for (AssetWarehouseDir dir : pageDirList) {
            if (!CollectionUtils.isEmpty(dir.getRoleIdList()) && containsAny(roleIdList, dir.getRoleIdList())) {
                result.add(dir);
            }
        }
        return result;
    }

    @Override
    public void migrationAssetModule() {
        ModuleNodeInfo assetModule = moduleSvc.getModuleTreeBySign(1L, null, "资产仓库");
        List<AssetWarehouseDir> newDirList = new ArrayList<>();
        List<Long> pageList = new ArrayList<>();
        // 获取所有页面
        if (BinaryUtils.isEmpty(assetModule.getChildren())) {
            throw new BinaryException("资产仓库下子目录不存在");
        }
        getPageList(assetModule.getChildren(), pageList);
        Map<Long, List<SysRoleModuleRlt>> roleModuleGroup = Collections.emptyMap();
        if (!CollectionUtils.isEmpty(pageList)) {
            List<SysRoleModuleRlt> rlts = roleModuleRltSvc.getListByQuery(1, 2000, QueryBuilders.termsQuery("moduleId", pageList)).getData();
            if (!CollectionUtils.isEmpty(rlts)) {
                roleModuleGroup = rlts.stream().collect(Collectors.groupingBy(SysRoleModuleRlt::getModuleId));
            }
        }
        migrationModuleAssetDir(assetModule.getChildren(), 0L, newDirList, 0, roleModuleGroup);
        List<AssetWarehouseDir> existDirList = assetWarehouseDirDao.getListByQuery(null);
        if (!CollectionUtils.isEmpty(existDirList)) {
            List<Long> existIdList = existDirList.stream().map(AssetWarehouseDir::getId).collect(Collectors.toList());
            newDirList.removeIf(next -> existIdList.contains(next.getId()));
        }
        if (!CollectionUtils.isEmpty(newDirList)) {
            assetWarehouseDirDao.saveOrUpdateBatch(newDirList);
        }
        List<AssetWarehouseDir> assetWarehousePageDirs = newDirList.stream().filter(e -> e.getModuleType().equals(3)).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(assetWarehousePageDirs)) {
            categorySvc.createTopCategoryByAssetDir(assetWarehousePageDirs);
        }
    }

    private void getPageList(List<ModuleNodeInfo> children, List<Long> modulePageList) {
        for (ModuleNodeInfo child : children) {
            // 设置权限
            if (!BinaryUtils.isEmpty(child.getModuleType()) && child.getModuleType().equals(3)) {
                modulePageList.add(child.getId());
            }
            if (!CollectionUtils.isEmpty(child.getChildren())) {
                getPageList(child.getChildren(),modulePageList);
            }
        }
    }

    private void migrationModuleAssetDir(List<ModuleNodeInfo> children, Long parentId, List<AssetWarehouseDir> newDirList, int order, Map<Long, List<SysRoleModuleRlt>> roleModuleGroup) {
        for (ModuleNodeInfo child : children) {
            AssetWarehouseDir target = new AssetWarehouseDir();
            BeanUtil.copyProperties(child, target);
            target.setOrderNo(order++);
            target.setParentId(parentId);
            target.setName(child.getLabel());
            // 设置权限
            if (!BinaryUtils.isEmpty(child.getModuleType()) && child.getModuleType().equals(3)) {
                List<SysRoleModuleRlt> sysRoleModuleRlts = roleModuleGroup.get(child.getId());
                if (CollectionUtils.isEmpty(sysRoleModuleRlts)) {
                    target.setRoleIdList(Lists.newArrayList(1L));
                } else {
                    target.setRoleIdList(sysRoleModuleRlts.stream().map(SysRoleModuleRlt::getRoleId).collect(Collectors.toList()));
                }
            }
            if (!BinaryUtils.isEmpty(target.getModuleUrl())&&target.getModuleUrl().contains("=")) {
                try {
                    target.setId(Long.valueOf(target.getModuleUrl().split("=")[1]));
                } catch (Exception e) {
                    log.error("页面URl处理错误"+e);
                }
            }
            newDirList.add(target);
            if (!CollectionUtils.isEmpty(child.getChildren())) {
                migrationModuleAssetDir(child.getChildren(), target.getId() ,newDirList, 0,roleModuleGroup);
            }
        }
    }

    @Override
    public AssetWarehouseDir getById(Long id) {
        return assetWarehouseDirDao.getById(id);
    }

}